package ithink.link.service;

import com.alibaba.fastjson.JSONObject;
import ithink.link.ConfigHelper;
import ithink.link.base.message.LinkMessage;
import ithink.link.bean.DeviceInfo;
import ithink.link.exception.ParameterErrorException;
import ithink.link.exception.ReconnectException;
import ithink.link.stack.IConnection;
import ithink.link.stack.MqConnection;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

public class WebManager {
    public class Transaction{
        public Transaction(IConnection connection, String sender) {
            this.connection = connection;
            ts = System.currentTimeMillis();
            this.sender = sender;
        }
        String sender;
        IConnection connection;
        long ts;
    }

    private static final Logger LOGGER = LoggerFactory.getLogger(WebManager.class);
    private Map<String, Transaction> transactionMap = new HashMap<>();

    private final Object transactionObj = new Object();
    private Timer transactionTimer = new Timer();
    private MqConnection mqConnection;


    public WebManager(MqConnection mqConnection) {
        this.mqConnection = mqConnection;
        transactionTimer.schedule(new TimerTask() {
            public void run() {
                checkTransactionTimeout();
            }
        }, 1000 , 1000*5);
    }


    private void checkTransactionTimeout() {
        synchronized (transactionObj) {
            for(String key : transactionMap.keySet()) {
                Transaction transaction = transactionMap.get( key );
                if(System.currentTimeMillis() - transaction.ts > 10 * 1000) {
                    LOGGER.info( "transaction key: {} timeout", key );
                    transactionMap.remove( key );
                }
            }
        }
    }



    public void deviceLogin(String sid) {
        checkDeviceRegister( sid );
        sendMessage(sid, "login");
    }

    public void deviceLogout(String sid) {
        sendMessage(sid, "logout");
    }

    public void checkDeviceRegister(String sid) {
        sendMessage(sid, "check-register");
    }

    private void sendMessage(String sid, String type) {
        LinkMessage message = new LinkMessage();
        JSONObject object = new JSONObject( );
        object.put( "sid", sid );
        object.put( "type", type );
        object.put( "sender", ConfigHelper.getName());
        object.put( "tag", "master" );
        message.setText( object );
        mqConnection.sendMessage(message);
    }

    public void registerTransaction(IConnection connection, LinkMessage message) {
        try {
            synchronized (transactionObj) {
                String key = getTransactionKey( message );
                if (transactionMap.containsKey( key )) {
                    LOGGER.warn( "the key {} already exsist, remove old", key );
                }
                LOGGER.info( "register transaction key = {}", key );
                transactionMap.put( key, new Transaction(connection, message.getText().getString( "sender" )));
            }
        } catch (ParameterErrorException e) {
            LOGGER.error("", e);
        }
    }

    public void response(LinkMessage message) {
        try {
            String key = getTransactionKey(message);
            synchronized (transactionObj) {
                if (!transactionMap.containsKey( key )) {
                    LOGGER.warn( "the key {} not exsist", key );
                    return;
                }
                Transaction transaction = transactionMap.get( key );
                message.getText().put( "tag",  transaction.sender);
                transaction.connection.sendMessage( message );
                transactionMap.remove(key);
            }

        } catch (ParameterErrorException e) {
            LOGGER.error("", e);
        }
    }

    public static String getTransactionKey(LinkMessage message) throws ParameterErrorException {
        String type = message.getText().getString("type");
        String sid = message.getText().getString("sid");
        String umac = message.getText().getString("umac");
        if(StringUtils.isBlank( type ) || StringUtils.isBlank( sid )||StringUtils.isBlank( umac )) {
            throw new ParameterErrorException(message.getText().toJSONString());
        }
        return type + ","+  "," + sid + "," +  umac;
    }
}
